import gc
import os
from .microWebSrv import MicroWebSrv, _response, _client
try:
    from shared_types import *
except ImportError:
    pass
RespType = _response
CliType = _client


def list_dir(httpClient: CliType, httpResponse: RespType, routeArgs=None):
    files = []
    for item in os.listdir():
        size = os.stat(item)[6]
        files.append({"size": size, "name": item})
    httpResponse.WriteResponseJSONOk(files)


def parse_multipart_form_data(data, is_all_data=False) -> "Tuple[str, bytes, bytes]":
    # 分隔符通常位于数据开始和结束的地方，以及每个部分的开始

    boundary = data.split(b'\r\n', 1)[0]

    # 分割整个数据为不同的部分
    parts = data.split(boundary)
    filename = b""
    content = b""
    # for p in parts:
    #     print(p)
    # print(parts)
    parts_iter = parts[1:-1] if len(parts) >= 3 else parts[1:]
    for part in parts_iter:  # 跳过第一个和最后一个部分（它们是空的）
        if is_all_data:
            # 去除前后空白字符
            part = part.strip()
        else:
            # 如果读取的数据不是全部，那么只去除左端的空格
            part = part.lstrip()
        # 找到Content-Disposition行
        if b'Content-Disposition' in part:
            # 分割头部和内容
            splitted = part.split(b'\r\n\r\n', 1)
            if len(splitted) == 2:
                header, content = splitted
            else:
                header, content = splitted[0], b''
            # 提取文件名和字段名
            header_lines = header.split(b'\r\n')
            print("header_lines", header_lines)
            for line in header_lines:
                if b'filename=' in line:
                    filename = line.split(b'filename=')[1].strip(b'\"')
                if b'name=' in line:
                    field_name = line.split(b'name=')[1].strip(b'\"')
            break
    return filename.decode("utf8"), content, boundary


def file_exists(filename: str):
    try:
        os.stat(filename)
        return True
    except OSError:
        return False


def mkdirs(path):
    # 分割路径，获取所有目录层级
    parts = path.split(os.sep)
    if not parts[0]:  # 如果路径以分隔符开始，则第一个元素为空字符串
        parts[0] = os.sep

    # 逐步构建路径并创建目录
    for i in range(len(parts)):
        sub_path = os.sep.join(parts[:i+1])
        if not file_exists(sub_path):
            try:
                os.mkdir(sub_path)
            except OSError as e:
                pass


def rmdir_recursive(d):
    """
    Recursively remove directories
    """
    try:
        if os.stat(d)[0] & 0x4000:  # Dir
            for f in os.ilistdir(d):
                if f[0] not in ('.', '..'):
                    rmdir_recursive("/".join((d, f[0])))  # File or Dir
            os.rmdir(d)
        else:  # File
            os.remove(d)
    except:
        print("rm of '%s' failed" % d)


def rm_file(httpClient: CliType, httpResponse: RespType, routeArgs=None):
    data: "RMFileRequest" = httpClient.ReadRequestContentAsJSON()
    try:
        if data['type'] == "directory":
            rmdir_recursive(data['name'])
        else:
            os.remove(data['name'])
        httpResponse.WriteResponseJSONOk(
            200, {"msg": f"successfully removed {data['type']} {data['name']}"})
    except OSError as e:
        httpResponse.WriteResponseJSONError(
            400, {"msg": f"error occurred when deleting item {data}: {e}"})


def resources_info(httpClient: CliType, httpResponse: RespType, routeArgs=None):
    """
    获取文件系统及内存占用信息
    """

    statvfs_fields = ['bsize', 'frsize', 'blocks',
                      'bfree', 'bavail', 'files', 'ffree',]
    info = dict(zip(statvfs_fields, os.statvfs('/')))
    info['total_size'] = info['blocks'] * info['frsize']

    allocated = gc.mem_alloc()
    free = gc.mem_free()
    resources_info: ResourceInfo = {
        "flash_total": info['blocks'] * info['frsize']/1024,
        "flash_used": (info['blocks'] - info['bfree']) * info['frsize']/1024,
        "mem_used": (allocated)/1024,
        "mem_total": (allocated+free)/1024
    }
    httpResponse.WriteResponseJSONOk(resources_info)


def upload_file(httpClient: CliType, httpResponse: RespType, routeArgs=None):
    # Read the head
    if httpClient.GetRequestContentLength() < 4096:
        filename, content, _ = parse_multipart_form_data(
            httpClient.ReadRequestContent(), is_all_data=True)
        splitted = filename.rsplit("/", 1)
        path = "." if len(splitted) == 1 else splitted[0]
        if not file_exists(path):
            mkdirs(path)
        # print("dir", path, "for", filename)
        with open(filename, 'wb') as f:
            f.write(content)
        httpResponse.WriteResponseJSONOk({f"Successfully put file {filename}"})
    else:
        remainingSize = httpClient.GetRequestContentLength()
        # while remainingSize > 0:
        data = httpClient.ReadRequestContent(1024)
        filename, content, boundary = parse_multipart_form_data(data)
        remainingSize -= 1024
        path = filename.rsplit("/", 1)[0]
        if not file_exists(path):
            mkdirs(path)
        with open(filename, 'wb') as f:
            f.write(content)
            while True:
                # 保证最后一次读取的数据长度必然>1024
                if remainingSize > 2048:
                    readSize = 1024
                elif 1024 < remainingSize <= 2048:
                    readSize = remainingSize
                else:
                    readSize = remainingSize
                content = httpClient.ReadRequestContent(readSize)

                remainingSize -= readSize
                # 如果全部都读取完了，就把边界裁剪掉，并且去除右侧\r\n空白字符
                if remainingSize == 0:
                    content = content.split(boundary)[0]
                    if content.endswith(b"\r\n"):
                        content = content[:-2]
                f.write(content)
                if remainingSize <= 0:
                    break
        httpResponse.WriteResponseJSONOk({f"Successfully put file {filename}"})
